/*
 * Copyright 2010 Dovado FZ-LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dovado.dovadoremote;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.TabActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TabHost;
import android.widget.Toast;

/* * This is the MAIN class which holds the other activities
 *
 * The class extends TabActivity which will make it show the tabs for Router, Info, Home Automation, About and Map.
 * The tabs are now implemented as Activities. There are most definitely ways of implementing tabs which are better
 * than this solution (for example having each tab as a View).
 * 
 * *********************************
 * Quick overview:
 * 
 * The app basically does these 2 things:
 * 1. Retrieving settings and information from the router (when pressing the refresh-button or logging in):
 * 	Set up a cleartext tcp/ip-connection to the router on port 6435.
 * 	Send username and password
 * 	Execute commands (for example "ts aliases" or "info") to retrieve settings/information which will be stored in the app.
 * 	Disconnect.
 * 
 * 2. Executing homeautomation events
 * 	Set up a cleartext tcp/ip-connection to the router on port 6435.
 * 	Send username and password
 * 	Execute command (for example "ts turn lamp off" or "ts dim mydimmer 80")
 * 	Disconnect
 * 
 * TIP for programmers: Test the API manually by accessing it via telnet on port 6435 and read the API documentation (available from http://www.dovado.com/api)
 * 
 * ********************************
 * Activities/classes/functions:
 * 
 * TABS:
 * 
 * 	Info: An activity which displays various settings and information retrieved from the router
 * 	
 * 	Homeautomation:  An activity which shows the actual switches which triggers homeautomation commands (such as "bedroomlamp ON")
 * 	
 * 	Map: A mapactivity whichDisplays a map showing the Dovado-logo on the router's current position
 * 
 * 	About: An activity that shows static guides and information about the application
 * 
 *  Routers: An activity that shows static information about the different Dovado routers
 * 
 * MENU:
 * 
 * 	Refresh: A static function which is found in Communicator.sync and can be used by others to retrieve settings, info and aliases from the router
 *  
 *  Login: An activity in which you set the password and host for the session followed by a refresh. Settings will be saved to a file.
 *
 * OTHER: 
 *
 * 	Communicator: The Communicator class holds the connection to the router and exports a couple of static functions 
 *	which is used by the other classes for I/O between phone<->router.
 * 
 *  SplashScreen: Shows the dovado splashscreen for 5 seconds or until the screen is touched
 *  
 *  Webactivator: If this app cannot connect to a given host (router) then the router might not be enabled for API access. 
 *  This function logs in to the router's web interface and enabled API over LAN access.
 *  
 * ***************
 * 
 * NOTE: There's a LOT of things to be implemented/improved. To name a few:
 * 1. We throw many warnings. These should be handled properly (for example try to re-transmit or alert the user)
 * 2. A complete re-build of the app to make a better "core" which is easier for users to extend
 * 3. Memory handling. Right now I've got no clue how memory efficient this app is but I'm sure it could be improved
 * 
 * 
 * For developers: 
 * to test the monkey type the following in a shell (with app running):
 * adb shell monkey -p com.dovado.dovadoremote -v 500 500
 * to see memory usage:
 * adb shell ps | grep dovado
 * 
 * */
public class DAAPP extends TabActivity {

	/*
	 * AsyncTask which displays "please wait" while we try to activate
	 * app-access through the router's web GUI:
	 */
	class ActivateSleep extends AsyncTask<String, String, String> {

		@Override
		protected String doInBackground(String... params) {

			publishProgress(getResources().getString(
					R.string.about_text_router_alert_wait_message));
			String response = Webactivator.activate();

			setWillActivate(response);

			return getResources().getString(R.string.doneexecuting);

		}

		@Override
		protected void onPostExecute(String result) {

			try {
				myProgressDialog.dismiss();
			} catch (Exception e) {
				// Yeah, we should do something here
			}
			if (getWillActivate() == "") {
				/*
				 * We will wait for the router to restart since we activated the
				 * API:
				 */
				new RestartSleep().execute("", "", "");
			} else {
				/*
				 * Sync NOK
				 */
				String errorMessage = getWillActivate();
				if (errorMessage.equalsIgnoreCase("firmware")) {
					errorMessage = getResources()
							.getString(
									R.string.about_text_router_alert_not_supported_alert_message);
				} else {
					errorMessage = getResources()
							.getString(
									R.string.about_text_router_alert_error_alert_message);
				}

				Toast.makeText(getApplicationContext(), errorMessage,
						Toast.LENGTH_LONG).show();

				// new ActivateSleep().execute("", "", "");

			}

		}

		@Override
		protected void onProgressUpdate(String... values) {

			myProgressDialog = ProgressDialog.show(DAAPP.this, getResources()
					.getString(R.string.waitheadline), values[0], true);
		}
	}

	/*
	 * AsyncTask which waits while the router is restarting after a successful
	 * API-activation
	 */
	class RestartSleep extends AsyncTask<String, String, String> {
		ProgressDialog pbarDialog = null;

		@Override
		protected String doInBackground(String... params) {
			publishProgress("WAIT WHILE RESTARTING!");

			int sleepCounter = 0;
			/*
			 * It takes about 80 seconds for the router to get back online:
			 */
			while (sleepCounter <= 80) {
				// publishProgress("Executing command..");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				publishProgress("" + sleepCounter);
				sleepCounter++;
			}

			return getResources().getString(R.string.doneexecuting);

		}

		@Override
		protected void onPostExecute(String result) {

			try {
				pbarDialog.dismiss();
			} catch (Exception e) {
				// Yeah, we should do something here
			}
			/*
			 * After a reboot (80 seconds) we want to sync:
			 */
			handleSync();
		}

		@Override
		protected void onProgressUpdate(String... values) {
			/*
			 * On first call just initialize a progressbar On the second and
			 * later calls display the current progress
			 */
			if (values[0].length() > 3) {

				pbarDialog = new ProgressDialog(DAAPP.this);

				pbarDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

				pbarDialog.setMax(80);
				pbarDialog.setMessage(getResources().getString(
						R.string.about_text_router_alert_sucessful_message));
				pbarDialog
						.setTitle(R.string.about_text_router_alert_sucessful_title);
				pbarDialog.setCancelable(false);
				pbarDialog.show();
			} else {
				pbarDialog.setProgress(Integer.parseInt(values[0]));
			}

		}
	}

	class SyncSleep extends AsyncTask<String, String, String> {

		@Override
		protected String doInBackground(String... params) {
			/*
			 * Wait for the settings-page to finish before we try to sync:
			 */
			while (!getHasStarted()) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			publishProgress(getResources().getString(R.string.syncing));

			// Sets hassynced to true or false:
			Communicator.sync();

			return getResources().getString(R.string.doneexecuting);

		}

		@Override
		protected void onPostExecute(String result) {

			try {
				myProgressDialog.dismiss();
			} catch (Exception e) {
				// Yeah, we should do something here
			}
			if (getIsSynced()) {
				/*
				 * Sync OK! Show a toast saying "sync successful":
				 */
				Toast.makeText(getApplicationContext(),
						getResources().getString(R.string.syncok),
						Toast.LENGTH_LONG).show();
			} else {
				/*
				 * Sync NOK Display error message OR show activationwindow:
				 */

				if (!Communicator.getShowAutoenable()) {
					Toast.makeText(getApplicationContext(),
							Communicator.getLoginMessage(), Toast.LENGTH_LONG)
							.show();
				} else {
					AlertDialog.Builder builder = new AlertDialog.Builder(
							DAAPP.this);
					builder.setTitle(getResources().getString(
							R.string.on_result_exception_dialog_title));
					builder.setMessage(
							getResources().getString(
									R.string.error_unknown_error))
							.setCancelable(false).setPositiveButton("Yes",
									new DialogInterface.OnClickListener() {
										public void onClick(
												DialogInterface dialog, int id) {

											dialog.cancel();
											DAAPP.setWillActivate("");
											new ActivateSleep().execute("", "",
													"");

										}
									}).setNegativeButton("No",
									new DialogInterface.OnClickListener() {
										public void onClick(
												DialogInterface dialog, int id) {
											dialog.cancel();
											DAAPP
													.setWillActivate("Will not activate app access");
										}
									});
					AlertDialog alert = builder.create();
					alert.show();
				}

			}

		}

		@Override
		protected void onProgressUpdate(String... values) {
			myProgressDialog = ProgressDialog.show(DAAPP.this, getResources()
					.getString(R.string.waitheadline), values[0], true);
		}
	}

	/*
	 * Constants for the menu:
	 */
	private static final int SYNC = 0;
	private static final int SETTINGS = 1;

	/*
	 * Have we synced the app<->router?
	 */
	public static boolean getHasSynced() {
		return hasSynced;
	}

	/*
	 * Did the last sync complete successfully?
	 */
	public static boolean getIsSynced() {
		return isSynced;
	}

	public static String getWillActivate() {
		return willActivate;
	}

	public static void setHasSynced(boolean inHasSynced) {
		hasSynced = inHasSynced;
	}

	public static void setIsSynced(boolean inIsSynced) {
		isSynced = inIsSynced;
	}

	public static void setSyncOnDemand() {
		syncOnDemand = true;
	}

	public static void setWillActivate(String inActivate) {
		willActivate = inActivate;
	}

	/*
	 * Default host and password if no settings have been made:
	 */
	private String host = "192.168.0.1";

	private String password = "password";

	private static final String settingsFilename = "/dovado_settings"; // will
	// point
	// to
	// sdcard/DAAPP/dovado_settings
	// if
	// that's
	// where
	// DAAPP
	// is
	// installed;

	/*
	 * Declare the Info-intent. It will be shown on startup since that's the
	 * active tab at execution.
	 */
	Intent routers_intent;

	// Do not show settings on screen rotation
	private static boolean hasStarted = false;

	// Local variable that knows if we have synced (any time):
	private static boolean hasSynced = false;

	// Local variable that knows if the last sync was successful:
	private static boolean isSynced = false;

	// Local variable that's [true] if our sync failed because of connectivity
	// problems
	// (then show "do you want to activate app access on your router")
	private static String willActivate;

	// The progressdialog which is displayed while the router is rebooting on
	// auto-enable:
	ProgressDialog myProgressDialog;

	// When we arrive here after initial settings (login)-screen then refresh
	// (sync):
	private static boolean syncOnDemand = false;

	/*
	 * Has the application started? This is used in order to bring up the
	 * settings-view the first time we start the app
	 */
	public static boolean getHasStarted() {
		return hasStarted;
	}

	public static void setHasStarted(boolean inStart) {
		hasStarted = inStart;
	}

	/*
	 * TODO: remove. this is not used
	 */
	protected void alertbox(String title, String mymessage) {
		new AlertDialog.Builder(this).setMessage(mymessage).setTitle(title)
				.setCancelable(true).setNeutralButton(android.R.string.ok,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int whichButton) {
							}
						}).show();
	}

	/*
	 * Sync is handled by an asynctask
	 */
	private void handleSync() {
		new SyncSleep().execute("", "", "");
	}

	/*
	 * TODO: remove. It does nothing
	 */
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}

	/*
	 * Are we going to activate the API on the router?
	 */

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		/* bring up settings - //Do not show settings on screen rotation */
		if (!hasStarted) {
			Intent settingsIntent = new Intent(this, Settings.class);
			startActivityForResult(settingsIntent, -1);
			handleSync();
		}

		/*
		 * show main layout (nothing there except for tabs)
		 */
		setContentView(R.layout.main);

		/*
		 * set up the tabs:
		 */
		TabHost mTabHost = getTabHost();

		Intent homeautomation_intent = new Intent().setClass(this,
				Homeautomation.class);
		Intent info_intent = new Intent().setClass(this, Info.class);
		Intent map_intent = new Intent().setClass(this, Map.class);
		Intent about_intent = new Intent().setClass(this, About.class);
		routers_intent = new Intent().setClass(this, Routers.class);
		TabHost.TabSpec automationTab = mTabHost.newTabSpec("Home Automation")
				.setIndicator("Automation").setContent(homeautomation_intent);
		TabHost.TabSpec infoTab = mTabHost.newTabSpec("Info").setIndicator(
				"Info").setContent(info_intent);
		TabHost.TabSpec mapTab = mTabHost.newTabSpec("Map").setIndicator("Map")
				.setContent(map_intent);
		TabHost.TabSpec aboutTab = mTabHost.newTabSpec("About").setIndicator(
				"About").setContent(about_intent);
		TabHost.TabSpec routersTab = mTabHost.newTabSpec("Products")
				.setIndicator("Routers").setContent(routers_intent);
		mTabHost.addTab(routersTab);
		mTabHost.addTab(infoTab);
		mTabHost.addTab(automationTab);
		mTabHost.addTab(mapTab);
		mTabHost.addTab(aboutTab);

		/*
		 * Get current settings from file and give it to the communicator:
		 */
		Communicator.setSettingsFile(this.getFilesDir().getAbsolutePath()
				+ settingsFilename);
		host = Communicator.getHost(Communicator.getSettingsFile());
		password = Communicator.getPassword(Communicator.getSettingsFile());

		/*
		 * Communicator will now hold the host and password;
		 */
		Communicator.setHost(host);
		Communicator.setPassword(password);

	}

	/*
	 * What's being displayed if menu-key is pressed:
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		menu.add(0, SYNC, 0, "Refresh");
		menu.add(0, SETTINGS, 0, "Login");
		return true;
	}

	/*
	 * AsyncTask while displays a "please wait" while we're refreshing:
	 */

	/*
	 * Handles item selections from the Menu
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		/*
		 * Sync pressed:
		 */
		case SYNC:
			handleSync();
			return true;
			/*
			 * Login (Settings) pressed
			 */
		case SETTINGS:
			/*
			 * start the Intent which displays settings
			 */
			Intent settingsIntent = new Intent(this, Settings.class);
			startActivityForResult(settingsIntent, 0);
			return true;

		}

		return false;
	}

	/*
	 * if we come here after fiddling with settings then sync.
	 */
	@Override
	public void onResume() {
		if (syncOnDemand) {
			handleSync();
			syncOnDemand = false;
		}
		super.onResume();
	}
}
